#include <iostream>
#include <cassert>
#include "terminal512.h"
const int MANUAL=1;
const int AUTO=0;

Terminal::~Terminal(void)
{
    delete[] this->darsenas;
   
}

bool Terminal::AlgunoEnDarsena(void)const
{
    bool res=true;
    int cont=0;
    while(cont<this->cantdarsenas && res==true)
    {
        res=this->darsenas[cont].vacia();
        cont++;
    }

    return !res;
}



int Terminal::cantDarsenas() const
{
    return cantdarsenas;
}

bool Terminal::esperandoChofer() const
{
    return estaTrabado;
}

int Terminal::internosEnDarsena(int nroDarsena) const
{
    assert(nroDarsena<cantdarsenas);
    int n;
    n=darsenas[nroDarsena].tamano();
    return n;
}

IdInterno Terminal::internoEnPosicion(int nroDarsena, int posicion) const
{

    assert(nroDarsena>=0 && nroDarsena<cantdarsenas);
    assert(posicion>=0 && int(posicion)<int(darsenas[nroDarsena].tamano()));
    iterCola<colectivoConViajes> it;
    it.crearItcola(darsenas[nroDarsena]);
    int cont;
    cont=posicion+1;
    IdInterno res;
    while(cont!=0)
    {
        res=it.proximocola().Elcolectivo().ID();
        cont--;
    }
    return res;
}

bool Terminal::esInterno(IdInterno i) const
{
    iterConj<colectivoConViajes> it;
    bool res;
    res=false;
    it.crearItc(ColectivosViajando.claves());
    //primero me fijo si el colectivo pertenece a alguno de los que
    //esta viajando
    while(it.tieneProximoc() && res==false)
    {
        res=it.proximoc().Elcolectivo().ID()==i;
    }
    int contaux;
    contaux=0;
    while(contaux<this->cantdarsenas && res==false)
    {
        iterCola<colectivoConViajes> it;
        it.crearItcola(darsenas[contaux]);

        while(it.tieneProximocola() && res==false)
        {
            res=it.proximocola().Elcolectivo().ID()==i;
        }
        contaux++;

    }
    return res;
}

IdChofer Terminal::quienManeja(IdInterno i) //const
{
    assert(esInterno(i));
    assert(viajando(i));
    iterConj<colectivoConViajes> it;
    it.crearItc(this->ColectivosViajando.claves());
    colectivoConViajes aux;
    bool resultado;
    resultado=false;
    while(resultado==false)
    {
       aux=it.proximoc();
       resultado=aux.Elcolectivo().ID()==i;
    }

   return ColectivosViajando.obtener(aux).ID();
}


bool Terminal::viajando(IdInterno i) const
{
    iterConj<colectivoConViajes> it;
    it.crearItc(this->ColectivosViajando.claves());
    bool res;
    res=false;
    while(it.tieneProximoc() && res==false)
    {
        res=it.proximoc().Elcolectivo().ID()==i;
    }

    return res;
}

bool Terminal::esChofer(IdChofer i) const
{
    conjAc<Chofer> jovenes(this->ChoferesEsperandoJovenes);
    bool resultado=false;
    while(resultado==false && jovenes.cardinal()>0)
    {
        resultado= jovenes.dameUno().ID()==i;
        jovenes.sinUno();

    }

    if (resultado==false)
    {
        conjAc<Chofer> viejos(this->ChoferesEsperandoViejos);
        while(resultado==false && viejos.cardinal()>0)
        {
             resultado=viejos.dameUno().ID()==i;
             viejos.sinUno();
        }
    }
    if (resultado==false)
    {

        iterConj<colectivoConViajes> it;
        colectivoConViajes aux;
        it.crearItc(this->ColectivosViajando.claves());
        while(it.tieneProximoc() && resultado==false)
        {
            aux=it.proximoc();
            resultado=this->ColectivosViajando.obtener(aux).ID()==i;
        }
    }
    return resultado;
}


Terminal::Terminal(int cantDarsenas, const ConjInterno &inter,  const ConjChofer &chof)
{
  
  
    assert(validaConstructor(cantDarsenas, inter, chof));
    this->cantdarsenas=cantDarsenas;
    int pibes;
    int viej;
    pibes=0;
    viej=0;
    iterConj<Chofer> it;
    it.crearItc(chof);
    this->estaTrabado=false;
   this->darsenas= new Cola <colectivoConViajes>[cantDarsenas];

    while(it.tieneProximoc())
    {
        if (it.proximoc().edad()< 40)
        {
            pibes++;
        }
        else
        {
            viej++;
        }
    }
    conjAc<Chofer> jov(pibes);
    conjAc<Chofer> oldie(viej);
    this->ChoferesEsperandoJovenes=jov;
    this->ChoferesEsperandoViejos=oldie;
    Chofer aux;
    it.crearItc(chof);
    while(it.tieneProximoc())
    {
        aux=it.proximoc();
        if (aux.edad()< 40)
        {
           this->ChoferesEsperandoJovenes.Ag(aux);
        }
        else
        {
            this->ChoferesEsperandoViejos.Ag(aux);
        }
    }

    iterConj<Interno> ite;
    ite.crearItc(inter);



    while(ite.tieneProximoc())
    {

       colectivoConViajes coleconviaj(0,ite.proximoc());
        this->darsenas[0].encolar(coleconviaj);
    }

  Cola<colectivoConViajes> sinnada;
    int cont;
    cont=1;
    while(cont<this->cantdarsenas)
    {
        this->darsenas[cont]=sinnada;
        cont++;
    }
      
}

Terminal& Terminal::llegaInterno(IdInterno i, int d)
{
    assert(this->esInterno(i));
    assert(this->viajando(i));
    assert(d>=0 && d<this->cantdarsenas);
    colectivoConViajes aux;
    iterConj<colectivoConViajes> it;
    Conj<colectivoConViajes> c;

    c = ColectivosViajando.claves();
    it.crearItc(c);
    bool loencontre;
    loencontre=false;
    while(it.tieneProximoc() && loencontre==false)
    {
        aux=it.proximoc();
        loencontre=aux.Elcolectivo().ID()==i;
    }


    Chofer chof;
    chof= this->ColectivosViajando.obtener(aux);
    cout << "El chofer que llega es: " << chof << endl;
    if (chof.edad()< 40)
    {
        this->ChoferesEsperandoJovenes.Ag(chof);
    }
    else
    {
        this->ChoferesEsperandoViejos.Ag(chof);
    }
 

    this->ColectivosViajando.borrar(aux);
    
    this->darsenas[d].encolar(aux);
    if (this->estaTrabado)
    {
    	return (this->saleInterno());
    }
    else
    {
    	return *this;
    }

}






const Chofer Terminal::elChofer(IdChofer i) const
{
    assert(this->esChofer(i));
    Chofer res;
    conjAc<Chofer> jovenes(this->ChoferesEsperandoJovenes);
    bool resultado=false;
    while(resultado==false && jovenes.cardinal()>0)
    {
        res=(jovenes.dameUno());
        resultado=res.ID()==i;
        jovenes.sinUno();

    }


    if (resultado==false)
    {
        conjAc<Chofer> viejos(this->ChoferesEsperandoViejos);
        while(resultado==false && viejos.cardinal()>0)
        {
             res=(viejos.dameUno());
             resultado=res.ID()==i;
             viejos.sinUno();
        }
    }
    if (resultado==false)
    {

        iterConj<colectivoConViajes> it;
        colectivoConViajes aux;
        it.crearItc(this->ColectivosViajando.claves());
        while(it.tieneProximoc() && resultado==false)
        {
            aux=it.proximoc();
            res=this->ColectivosViajando.obtener(aux);
            resultado=res.ID()==i;

        }
    }
    return (res);
}




const Interno Terminal::elInterno(IdInterno i) const
{
	assert(this->esInterno(i));
	Conj<colectivoConViajes> c;  
    colectivoConViajes p;
    iterConj<colectivoConViajes> it;
    bool res = false;
    
    c = ColectivosViajando.claves();       
    it.crearItc(c);
    
    while(it.tieneProximoc() && res==false)
    {
        p=(it.proximoc());
        res=p.Elcolectivo().ID()==i;
    }
    int contaux;
    contaux=0;
    while (contaux < this->cantdarsenas && res==false)
    {
        iterCola<colectivoConViajes> it;
        it.crearItcola(darsenas[contaux]);

        while(it.tieneProximocola() && res==false)
        {
            p=(it.proximocola());
            res=p.Elcolectivo().ID()==i;           
        }
        contaux++;

    }
	return p.Elcolectivo();
}

Terminal& Terminal::saleInterno()
{
    assert(this->AlgunoEnDarsena());

    colectivoConViajes MinManual;
    colectivoConViajes MinAuto;
    colectivoConViajes aux;
    colectivoConViajes colectivoPorDefault;
    int darsenaManual = 0;
    int darsenaAuto = 0;
    int cantManual = 0;
    int cantAuto = 0;
    int cont=0;
    bool vaciaManual = true;
    bool vaciaAuto = true;
    bool yadespache=false;
    Chofer elquesale;
    
  
    //Primero me fijo cuales son los colectivos con posibilidades de salir
    //Busco el que tiene menos viajes para el caso en el que el colectivo sea manual
    // y lo mismo en el caso de que el colectivo sea automatico
    while(cont<this->cantdarsenas)
    {
         if (! (darsenas[cont].vacia()))
         {
             aux=darsenas[cont].proximo();
             if (aux.Elcolectivo().transmision()==MANUAL)
             {
                    //Si tiene menos viajes, o si es el primero que encuentro del tipo manual
                    if (aux.viajesHechos() <= MinManual.viajesHechos() || (cantManual == 0))
                    {
                    	//Si tienen igual cantidad de viajes, me fijo cual es el mas chico
                        if (aux.viajesHechos() == MinManual.viajesHechos()) {
                        	if (aux.Elcolectivo() < MinManual.Elcolectivo() || (cantManual == 0)) {
								MinManual=aux;
								darsenaManual=cont;
								vaciaManual=false;
							}
						}
						else {
							MinManual=aux;
							darsenaManual=cont;
							vaciaManual=false;
						}
					}
					cantManual++;
			}
			else
			{
				//Si tiene menos viajes, o si es el primero que encuentro del tipo automatico
				if (aux.viajesHechos() <= MinAuto.viajesHechos() || (cantAuto == 0))
                {
                	//Si tienen igual cantidad de viajes, me fijo cual es el mas chico
					if (aux.viajesHechos() == MinAuto.viajesHechos()) {
						if (aux.Elcolectivo() < MinAuto.Elcolectivo() || (cantAuto == 0)) {
								MinAuto=aux;
								darsenaAuto=cont;
								vaciaAuto=false;
							}
                    }
					else {
							MinAuto=aux;
							darsenaAuto=cont;
							vaciaAuto=false;
                    }
                }
                cantAuto++;

			}

         }
         //Paso a la siguiente darsena
         cont++;
     }
	 //Aumento los viajes de los dos. Al final, solo se va a terminar modificando uno de estos.
     MinAuto.hacerviaje();
     MinManual.hacerviaje();
     
     //Me fijo si la terminal esta trabada
     //a) No tengo choferes
     //b) Sale un automatico, pero no tengo conductores jovenes
     //c) No sale ningun colectivo
	 this->estaTrabado= (this->ChoferesEsperandoJovenes.cardinal() + this->ChoferesEsperandoViejos.cardinal()==0) || 
						(cantAuto>0 && cantManual==0 && this->ChoferesEsperandoJovenes.cardinal()==0)  || 
						(cantAuto+cantManual==0);
						
	//Si solo sale un automatico y no puede salir un manual					
     if ((cantAuto != 0) && (cantManual == 0) && ! (this->estaTrabado)  )
     {
		 this->darsenas[darsenaAuto].desencolar();
         elquesale=this->ChoferesEsperandoJovenes.dameUno();
         this->ChoferesEsperandoJovenes.sinUno();
         yadespache=true;
         this->ColectivosViajando.definir(MinAuto,elquesale);
      }
     //Si tengo para sacar un bondi manual, pero ninguno automatico
     //O si no tengo ningun chofer joven, tambien entro en este caso porque tengo que si o si
     //sacar al manual
    if (((cantAuto == 0) && (cantManual != 0) && ! (this->estaTrabado)  && !(yadespache) )
               || (this->ChoferesEsperandoJovenes.cardinal()==0 && !(yadespache) && ! (this->estaTrabado) ))
    {
             this->darsenas[darsenaManual].desencolar();
         //Veo que chofer saco, y ademas, lo saco de la espera
         elquesale=this->DameUnChofer();
         yadespache=true;
         this->ColectivosViajando.definir(MinManual,elquesale);
         
     }
     //Si no esta trabada, y todavia no despache, es decir,
     //puedo sacar tanto el colectivo manual como el automatico
     if(!(this->estaTrabado) && !(yadespache))
     {
         
         //Si el bondi manual es menor que el de automaticos
         if((MinAuto.viajesHechos()>MinManual.viajesHechos()) ||
                 (MinAuto.viajesHechos()==MinManual.viajesHechos() && MinAuto.Elcolectivo().ID()>MinManual.Elcolectivo().ID()))
         {
             //Saco el bondi manual
             this->darsenas[darsenaManual].desencolar();
             elquesale=this->DameUnChofer();
             yadespache=true;
             this->ColectivosViajando.definir(MinManual,elquesale);
         }
         else
         {
         	 //En caso contrario, el automatico va a ser menor que el manual
         	 //por lo que lo saco
             this->darsenas[darsenaAuto].desencolar();
             elquesale=this->ChoferesEsperandoJovenes.dameUno();
             this->ChoferesEsperandoJovenes.sinUno();
             yadespache=true;
             this->ColectivosViajando.definir(MinAuto,elquesale);
         }
     }
    return *this;

}

Chofer Terminal::DameUnChofer(void)
 {
     bool noSaque=true;
     Chofer res;
     if (this->ChoferesEsperandoJovenes.cardinal()>0 && this->ChoferesEsperandoViejos.cardinal()>0)
     {
         if (this->ChoferesEsperandoJovenes.dameUno().ID()>this->ChoferesEsperandoViejos.dameUno().ID())
         {
             res=this->ChoferesEsperandoViejos.dameUno();
             this->ChoferesEsperandoViejos.sinUno();
             noSaque=false;
         }
         else
         {

             res=this->ChoferesEsperandoJovenes.dameUno();
             this->ChoferesEsperandoJovenes.sinUno();
             noSaque=false;
         }
     }
     if (noSaque && this->ChoferesEsperandoJovenes.cardinal()==0)
     {
         res=this->ChoferesEsperandoViejos.dameUno();
         this->ChoferesEsperandoViejos.sinUno();
         noSaque=false;
     }
     if (noSaque)
     {
         res=this->ChoferesEsperandoJovenes.dameUno();
         this->ChoferesEsperandoJovenes.sinUno();
     }
     return res;
}
int Terminal::cantViajesInterno(IdInterno i) const
{
    colectivoConViajes col;
    iterConj<colectivoConViajes> it;
    bool res;
    res=false;
    it.crearItc(ColectivosViajando.claves());
    while(it.tieneProximoc() && res==false)
    {
        col=it.proximoc();
        res=col.Elcolectivo().ID()==i;
    }
    int contaux;
    contaux=0;
    while(contaux<this->cantdarsenas && res==false)
    {
        iterCola<colectivoConViajes> it;
        it.crearItcola(darsenas[contaux]);

        while(it.tieneProximocola() && res==false)
        {
            col=it.proximocola();
            res=col.Elcolectivo().ID()==i;
        }
        contaux++;

    }

         return col.viajesHechos();
}


bool Terminal::validaConstructor(int cantDarsenas, const ConjInterno &inter, const ConjChofer &chof)
{
    bool res;
    res=cantDarsenas>0;
   //res=res && ((chof.cantelem()>0 && inter.cantelem()>0) || (chof.cantelem()==0 && inter.cantelem()==0));

    int automatico=0;
    int jovenes=0;

    iterConj<Chofer> it;
    it.crearItc(chof);
    while(it.tieneProximoc())
    {
        if (it.proximoc().edad()<=40)
        {
            jovenes++;
        }

    }
    iterConj<Interno> ite;
    ite.crearItc(inter);
     while(ite.tieneProximoc())
    {
        if (ite.proximoc().transmision()!=MANUAL)
        {
            automatico++;
        }

    }
    if (automatico>0)
    {
        res=res&&jovenes>0;
    }

    return res ;
}
